package xyz.coderl;

import com.aliyun.fsi.insurance.agrmtexecution.claim.facade.dto.ClaimDTO;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;

import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;

/**
 * Json请求快速生成工具1.0
 *
 * @author 李坤尧
 * @date 2020-12-28
 */
public class JsonUtil {
    /**
     * 基本类型集合
     */
    private static final List<Class<?>> CLASS_LIST = new ArrayList<>();
    static {
        CLASS_LIST.add(byte.class);
        CLASS_LIST.add(Byte.class);
        CLASS_LIST.add(short.class);
        CLASS_LIST.add(Short.class);
        CLASS_LIST.add(int.class);
        CLASS_LIST.add(Integer.class);
        CLASS_LIST.add(long.class);
        CLASS_LIST.add(Long.class);
        CLASS_LIST.add(float.class);
        CLASS_LIST.add(Float.class);
        CLASS_LIST.add(double.class);
        CLASS_LIST.add(Double.class);
        CLASS_LIST.add(char.class);
        CLASS_LIST.add(Character.class);
        CLASS_LIST.add(boolean.class);
        CLASS_LIST.add(Boolean.class);

        CLASS_LIST.add(String.class);
        CLASS_LIST.add(Date.class);
        CLASS_LIST.add(Enum.class);
        CLASS_LIST.add(BigDecimal.class);
    }

    public static void main(String[] args) {
        System.out.println(objToJson(ClaimDTO.class));
    }

    /**
     * 将json对应的实体类的类对象转Json串
     *
     * @param clazz 对象的类对象
     * @return json串
     */
    public static String objToJson(Class< ? > clazz) {
        StringBuilder json = new StringBuilder("{");
        objectFieldToJson(clazz, json);
        json.append("}");
        return json.toString();
    }

    /**
     * 反射遍历当前对象的属性
     *
     * @param clazz 属性对象的class对象
     * @param json  json串
     */
    private static void objectFieldToJson(Class<?> clazz, StringBuilder json) {
        try {
            // 获取属性集合
            Field[] declaredFields = clazz.getDeclaredFields();

            // 遍历属性集合
            for (int i = 0; i < declaredFields.length; i++) {
                // 获取属性Field对象
                Field field = declaredFields[i];
                field.setAccessible(true);
                // 获取属性名
                String fieldName = field.getName();
                // 不加入序列化ID
                if ("serialVersionUID".equals(fieldName)) {
                    continue;
                }

                // 获取属性class对象
                Class<?> fieldType = field.getType();
                // 判断属性类型
                if (fieldType.equals(List.class)) {
                    fieldListToJson(field, json, fieldName, declaredFields.length - 1 == i);
                } else if (fieldType.equals(Map.class)) {
                    fieldMapToJson(field, json, fieldName, declaredFields.length - 1 == i);
                } else if (CLASS_LIST.contains(fieldType)) {
                    // 为基本类型
                    fieldToJson(fieldName, json, declaredFields.length - 1 == i);
                } else {
                    // 为对象
                    objNameAndFieldToJson(json, fieldName, fieldType, declaredFields.length - 1 == i);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 普通field属性拼接
     *
     * @param fieldName  属性名
     * @param json       json串
     * @param isLast     是否为filed集合最后一个
     */
    private static void fieldToJson(String fieldName, StringBuilder json, boolean isLast) {
        json.append("\"").append(fieldName).append("\":");
        basicToJson(json);
        if (!isLast) {
            json.append(",");
        }
    }

    /**
     * 递归拼接对象时先拼接对象名和大括号
     *
     * @param json      json串
     * @param fieldName 属性对象名
     * @param fieldType 属性对象的class对象
     * @param isLast    是否拼接,
     */
    public static void objNameAndFieldToJson(StringBuilder json, String fieldName, Class<?> fieldType, boolean isLast) {
        // 拼接对象名
        json.append("\"").append(fieldName).append("\":{");
        // 拼接对象值(继续反射遍历当前对象的属性)
        objectFieldToJson(fieldType, json);
        // 拼接结尾并判断是否需要继续拼接对象
        json.append("}").append(isLast ? "" : ",");
    }

    /**
     * List集合转Json 长度为1
     *  @param field field对象
     * @param json json串
     * @param fieldName List集合名
     * @param isLast 是否拼接,
     */
    private static void fieldListToJson(Field field, StringBuilder json, String fieldName, boolean isLast) {
        // 为List集合
        // 获取List集合泛型
        ParameterizedType type = (ParameterizedType) field.getGenericType();

        json.append("\"").append(fieldName).append("\":");
        childTypeListToJson(type, json);
        json.append(isLast ? "" : ",");
    }

    /**
     * Map集合转Json 长度为1
     *  @param field field对象
     * @param json json串
     * @param fieldName List集合名
     * @param isLast 是否拼接,
     */
    private static void fieldMapToJson(Field field, StringBuilder json, String fieldName, boolean isLast) {
        ParameterizedType type = (ParameterizedType) field.getGenericType();

        json.append("\"").append(fieldName).append("\":");
        childTypeMapToJson(type, json);
        json.append(isLast ? "" : ",");
    }

    /**
     * 嵌套List类型的childType转json
     *
     * @param type 子type
     * @param json json串
     */
    private static void childTypeListToJson(ParameterizedType type, StringBuilder json) {
        Type actualTypeArgument = type.getActualTypeArguments()[0];
        json.append("[");
        if (actualTypeArgument instanceof Class) {
            Class<?> childClazz = (Class<?>) actualTypeArgument;
            if (CLASS_LIST.contains(childClazz)) {
                basicToJson(json);
            } else {
                json.append("{");
                objectFieldToJson(childClazz, json);
                json.append("}");
            }
        } else {
            ParameterizedType childType = (ParameterizedType) actualTypeArgument;
            Type rawType = childType.getRawType();
            if (rawType.equals(List.class)) {
                childTypeListToJson(childType, json);
            } else if (rawType.equals(Map.class)) {
                childTypeMapToJson(childType, json);
            }
        }
        json.append("]");
    }

    /**
     * 嵌套Map类型的childType转json
     *
     * @param type 子type
     * @param json json串
     */
    private static void childTypeMapToJson(ParameterizedType type, StringBuilder json) {
        Type keyType = type.getActualTypeArguments()[0];
        Type valueType = type.getActualTypeArguments()[1];
        json.append("{");
        // 对key进行解析判断
        if (keyType instanceof Class) {
            Class<?> childClazz = (Class<?>) keyType;
            if (CLASS_LIST.contains(childClazz)) {
                basicToJson(json);
            } else {
                objectFieldToJson(childClazz, json);
            }
        } else {
            ParameterizedType childType = (ParameterizedType) keyType;
            Type rawType = childType.getRawType();
            if (rawType.equals(List.class)) {
                childTypeListToJson(childType, json);
            } else if (rawType.equals(Map.class)) {
                childTypeMapToJson(childType, json);
            }
        }
        json.append(":");
        // 对value进行解析判断
        if (valueType instanceof Class) {
            assert keyType instanceof Class<?>;
            Class<?> childClazz = (Class<?>) keyType;
            if (CLASS_LIST.contains(childClazz)) {
                basicToJson(json);
            } else {
                objectFieldToJson(childClazz, json);
            }
        } else {
            ParameterizedType childType = (ParameterizedType) valueType;
            Type rawType = childType.getRawType();
            if (rawType.equals(List.class)) {
                childTypeListToJson(childType, json);
            } else if (rawType.equals(Map.class)) {
                childTypeMapToJson(childType, json);
            }
        }
        json.append("}");
    }

    /**
     * 将基本数据类型赋初始值 空
     *
     * @param json json串
     */
    private static void basicToJson(StringBuilder json) {
        json.append("\"\"");
    }
}